package com.xiaomaoguai.fcp.pre.plouto.mailbox.autoconfigure;

import com.dh.mailbox2.annotation.DMailBox;
import com.dh.mailbox2.api.Mailbox;
import com.dh.mailbox2.internal.enums.HandleStatus;
import com.dh.mailbox2.internal.utils.CommonBeanCopier;
import com.dh.mailbox2.retrymailbox.RetryMSG;
import com.dh.mailbox2.retrymailbox.RetryMailBox;
import com.dh.mailbox2.retrymailbox.strategy.RetryStrategy;
import com.dh.mailbox2.spi.Mailboxs;
import com.dh.mailbox2.wrapper.AbstractMailBox;
import com.dh.mailbox2.wrapper.MSG;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.web.context.support.GenericWebApplicationContext;

import javax.annotation.Resource;
import java.util.LinkedHashMap;
import java.util.Map;


@Slf4j
public class MailBoxes extends Mailboxs implements ApplicationListener<ContextRefreshedEvent> {

	private static Map<String, Object> mailboxesMap;

	/**
	 * 重试邮箱
	 */
	@Resource
	private RetryMailBox retryMailBox;

	@Override
	public void onApplicationEvent(ContextRefreshedEvent event) {
		//feign调用下游接口时，防止用空值刷新mailbox
		ApplicationContext applicationContext = event.getApplicationContext();
		if (applicationContext instanceof GenericWebApplicationContext) {
			mailboxesMap = event.getApplicationContext().getBeansWithAnnotation(DMailBox.class);
			for (Map.Entry<String, Object> entry : mailboxesMap.entrySet()) {
				log.info(entry.getKey() + " is registered thread：{}", ((AbstractMailBox) entry.getValue()).getNThreads());
			}
			log.info("=====mailbox are registered completely=====" + event.getSource().getClass().getName());
		}
	}

	/**
	 * 将消息发送到指定邮箱
	 *
	 * @param mailboxName
	 * @param msg
	 * @return
	 */
	@Override
	public boolean call(String mailboxName, MSG msg) {
		try {
			AbstractMailBox mailbox = getMailbox(mailboxName);
			if (mailbox != null) {
				msg.setCurrentName(mailboxName);
				return mailbox.call(msg);
			}
		} catch (Exception e) {
			log.error("调用Mailbox失败", e);
		}
		return false;
	}

	/**
	 * 广播 将信息发送到所有邮箱
	 *
	 * @param msg
	 * @return 成功发送邮箱数
	 */
	@Override
	public int callA(MSG msg) {
		int num = 0;
		for (Object mailbox : mailboxesMap.values()) {
			if (((Mailbox) mailbox).call(msg)) {
				num++;
			}
		}
		return num;
	}

	/**
	 * 多邮箱传递
	 *
	 * @param msg
	 * @return 成功发送邮箱数
	 */
	@Override
	public int callM(MSG msg) {
		int num = 0;
		LinkedHashMap<String, HandleStatus> targets = msg.getTargets();
		if (targets == null || targets.size() == 0) {
			return num;
		}
		for (Map.Entry<String, HandleStatus> e : targets.entrySet()) {
			if (mailboxesMap.containsKey(e.getKey())) {
				Mailbox mailbox = (Mailbox) mailboxesMap.get(e.getKey());
				if (mailbox.call(msg)) {
					num++;
				}
			}
		}
		return num;
	}

	/**
	 * 向重试邮箱传递消息
	 *
	 * @param msg
	 * @param retryStrategy
	 * @param maxRetryTimes
	 * @return
	 */
	@Override
	public void callRetry(MSG msg, RetryStrategy retryStrategy, Long maxRetryTimes) {
		RetryMSG retryMSG;
		if (msg instanceof RetryMSG) {
			retryMSG = ((RetryMSG) msg).nextTime();
			if (retryMSG.isEnd()) {
				return;
			}
		} else {
			retryMSG = new RetryMSG(retryStrategy).nextTime();
			CommonBeanCopier.copy(msg, retryMSG);
			retryMSG.setMaxretryTimes(maxRetryTimes == null ? -1L : maxRetryTimes);
		}
		log.debug("call retry mailbox,msg:[{}]", retryMSG.toString());
		retryMailBox.call(retryMSG);
	}

	public static AbstractMailBox getMailbox(String mailboxName) {
		return (AbstractMailBox) mailboxesMap.get(mailboxName);
	}

}
